home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EuroCD 3
/
EuroCD 3.iso
/
Programming
/
vbcc
/
pasm
/
pass.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-24
|
12KB
|
455 lines
/* $VER: pasm pass.c V0.6 (26.10.97)
*
* This file is part of pasm, a portable PowerPC assembler.
* Copyright (c) 1997 Frank Wille
*
* pasm is freeware and part of the portable and retargetable ANSI C
* compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
* pasm may be freely redistributed as long as no modifications are
* made and nothing is charged for it. Non-commercial usage is allowed
* without any restrictions.
* EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
* SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
*
*
* v0.6 (26.10.97) phx
* Bug in conditional assembly fixed.
* @object and @function symbols are always defined before
* pass 1 is executed.
* v0.5 (12.10.97) phx
* Support for user symbol definitions by -D option.
* The opcode field is automatically converted to lower case,
* so upper case directives and instructions are also allowed.
* v0.3 (10.04.97) phx
* Some vbcc-specific changes.
* v0.2 (25.03.97) phx
* Writes ELF object for 32-bit PowerPC big-endian. Either absolute
* or ELF output format may be selected. ELF is default for all
* currently supported platforms. PPCasm supports nine different
* relocation types (there are much more...).
* Compiles and works also under NetBSD/amiga (68k).
* Changed function declaration to 'new style' in all sources
* (to avoid problems with '...' for example).
* v0.1 (11.03.97) phx
* First test version with all PowerPC instructions and most
* important directives. Only raw, absolute output.
* v0.0 (15.02.97) phx
* File created.
*/
#define PASS_C
#include "ppcasm.h"
void exec_pass1(struct GlobalVars *);
void pass1(struct GlobalVars *,struct SourceText *,
struct MacroParams *,struct SourceThread *);
struct SourceText *include_source(struct GlobalVars *,char *);
void exec_pass2(struct GlobalVars *);
void pass2(struct GlobalVars *,struct SourceText *,
struct MacroParams *,struct SourceThread *);
struct SourceText *get_source(struct GlobalVars *);
static char *insert_macro_params(struct GlobalVars *,struct ParsedLine *,
char *,struct MacroParams *);
static char *readline(struct GlobalVars *,struct ParsedLine *,char *);
static char *getlabel(struct GlobalVars *,char *);
static struct SourceText *add_source(struct GlobalVars *,char *,char *,long);
static void prepare_sections(struct GlobalVars *);
void exec_pass1(struct GlobalVars *gv)
{
struct Symbol *sym;
char asmname[20];
char **p,*xmnemobuf,*usrdefbuf;
size_t xmsize=0,udsize=0;
struct UserDefine *nextudn;
struct UserDefine *udn = (struct UserDefine *)gv->userdeflist.first;
sprintf(asmname,PNAME "_V%d.%02d",VERSION,REVISION);
sym = add_symbol(gv,asmname,SYM_ABS,0);
sym->bind = SYMB_LOCAL;
gv->lcsym = add_symbol(gv,"$",SYM_RELOC,0);
gv->nargsym = add_symbol(gv,"$NARG",SYM_ABS,0);
add_symbol(gv,"@object",SYM_ABS,1);
add_symbol(gv,"@function",SYM_ABS,2);
gv->ifcond[0] = TRUE;
pass1(gv,add_source(gv,"<standard sections>",stdsects,
strlen(stdsects)),NULL,NULL);
if (!gv->noregsymbols)
pass1(gv,add_source(gv,"<standard definitions>",stdsets,
strlen(stdsets)),NULL,NULL);
while (nextudn = (struct UserDefine *)udn->n.next) {
udsize += strlen(udn->line);
udn = nextudn;
}
if (udsize) {
usrdefbuf = alloc(udsize+1);
*usrdefbuf = 0;
while (udn = (struct UserDefine *)remhead(&gv->userdeflist)) {
strcat(usrdefbuf,udn->line);
free(udn->line);
free(udn);
}
gv->usrdefs = TRUE;
pass1(gv,add_source(gv,"<user definitions>",usrdefbuf,udsize),
NULL,NULL);
}
if (!gv->noextmnemo) {
p = xmnemos;
while (*p) {
xmsize += strlen(*p);
p++;
}
xmnemobuf = alloc(xmsize+1);
*xmnemobuf = 0;
p = xmnemos;
while (*p) {
strcat(xmnemobuf,*p);
p++;
}
pass1(gv,add_source(gv,"<extended mnemonics>",xmnemobuf,xmsize),
NULL,NULL);
}
pass1(gv,include_source(gv,gv->source_name),NULL,NULL);
if (gv->vc) {
activate_section(gv,(struct Section *)gv->sectionlist.first);
alignment(gv,2);
pcadd(gv,4);
}
}
void pass1(struct GlobalVars *gv,struct SourceText *srctxt,
struct MacroParams *macro,struct SourceThread *prev_st)
/* Assembler Pass 1 */
{
struct SourceThread st;
unsigned long nlines = srctxt->nlines;
char *lp,c;
struct ParsedLine *pl = srctxt->plin;
/* init SourceThread structure */
st.prev = prev_st;
st.macro = macro;
st.csource = srctxt;
st.srcptr = srctxt->text; /* current source pointer */
st.line = 1;
st.macskip = NULL;
gv->cthread = &st; /* set current source thread */
while (nlines--) {
gv->absline++;
pl->lineptr = st.lineptr = st.srcptr;
/* get next line of source text */
if (macro && gv->ifcond[gv->iflevel]) { /* insert macro parameters? */
st.srcptr = insert_macro_params(gv,pl,st.srcptr,macro);
}
else {
st.srcptr = readline(gv,pl,st.srcptr);
}
lp = gv->linebuf;
/* evaluate label field */
lp = getlabel(gv,lp);
if (*gv->strbuf)
if (!st.macskip && gv->ifcond[gv->iflevel])
add_symbol(gv,gv->strbuf,SYM_RELOC,gv->csect->pc);
lp = skipspaces(lp);
/* evaluate opcode field */
lp = getsymbol(gv,lp);
if (*gv->strbuf) {
lower_case(gv->strbuf); /* convert opcode to lower case */
if (st.macskip) { /* macros */
if (!strcmp(gv->strbuf,".endm")) {
st.macskip->nlines = gv->absline - st.macskip->nlines;
add_macro(gv,st.macskip);
st.macskip = NULL;
}
}
else if (!gv->ifcond[gv->iflevel]) { /* conditional assembly */
if (!strncmp(gv->strbuf,".if",3))
gv->ifignore++;
else if (!strcmp(gv->strbuf,".else")) {
if (gv->ifignore == 0)
gv->ifcond[gv->iflevel] = TRUE;
}
else if (!strcmp(gv->strbuf,".endif")) {
if (gv->ifignore)
gv->ifignore--;
else
gv->iflevel--;
}
}
else { /* search opcode */
c = *lp; /* branch hint given? */
if (c=='+') {
lp++;
pl->branch_hint = 1;
}
else if (c=='-') {
lp++;
pl->branch_hint = -1;
}
search_opcode(gv,pl,gv->strbuf,skipspaces(lp));
}
}
if (!(pl->flags&PLF_NONEWLINE))
st.line++;
++pl;
}
gv->cthread = prev_st;
}
static char *insert_macro_params(struct GlobalVars *gv,struct ParsedLine *pl,
char *s,struct MacroParams *mp)
{
char **par = mp->param;
char c,callidbuf[16];
char *pp,*d=gv->linebuf;
int n;
do {
if ((c=*s++) == '\\') {
if (*s>='0' && *s<='9') { /* macro parameter? */
n = (int)(*s++ - '0');
if (pp = par[n]) {
while (*d++ = *pp++); /* insert parameter */
d--;
continue;
}
else {
error(9,n); /* reference to undefined macro parameter n */
continue;
}
}
else if (*s=='@') { /* insert macro call id */
s++;
pp = callidbuf;
sprintf(pp,"$%d",(int)mp->call_id);
while (*d++ = *pp++);
d--;
continue;
}
}
*d++ = c;
}
while (c!=0 && c!=1);
if (c==1) {
*(--d) = 0;
pl->flags |= PLF_NONEWLINE;
}
return (s);
}
static char *readline(struct GlobalVars *gv,struct ParsedLine *pl,char *s)
{
char c,*d = gv->linebuf;
do {
c = *s++;
*d++ = c;
}
while (c!=0 && c!=1);
if (c==1) {
*(--d) = 0;
pl->flags |= PLF_NONEWLINE;
}
return (s);
}
static char *getlabel(struct GlobalVars *gv,char *s)
/* read label to gv->strbuf, s points to the beginning of a line */
{
char *s_old = s;
s = getsymbol(gv,s); /* read label to buffer */
if ((s != s_old) && (*s == ':')) /* colon indicates a valid label */
return (++s);
*gv->strbuf = 0;
return (s_old);
}
struct SourceText *include_source(struct GlobalVars *gv,char *name)
/* called when encountering an .include directive */
{
char *s = mapfile(gv,name);
long len = *(size_t *)(s - sizeof(size_t)); /* mapfile stores size here */
return (add_source(gv,name,s,len));
}
static struct SourceText *add_source(struct GlobalVars *gv,char *name,
char *s, /* source text pointer */
long len) /* text length in bytes */
/* create a new SourceText node and add it to the source list */
{
struct SourceText *stxt = alloc(sizeof(struct SourceText));
bool comm=FALSE;
char quote=0;
stxt->name = name;
stxt->text = s;
stxt->nlines = 0;
/* replace '\n' and ';' by \0 and determine number of lines */
for (; len>0; len--,s++) {
switch (*s) {
case '\n':
*s = 0;
stxt->nlines++;
comm = FALSE; /* \n ends a comment */
break;
case '\r': /* ignore CRs */
*s = 0;
break;
case ';': /* ';' allows multiple statements per line */
if (!comm && !quote) {
if (*(s+1)=='\n' || *(s+1)=='\r')
*s = ' ';
else {
*s = 1;
stxt->nlines++;
}
}
break;
case '#': /* comment: ignore ';' in rest of line */
comm = TRUE;
break;
case 0x22: /* ignore ';' in strings too */
if (quote==0x22)
quote = 0;
else if (!quote)
quote = 0x22;
break;
case 0x27:
if (quote==0x27)
quote = 0;
else if (!quote)
quote = 0x27;
break;
}
}
stxt->plin = alloczero(stxt->nlines * sizeof(struct ParsedLine));
addtail(&gv->sourcelist,&stxt->n);
return (stxt);
}
static void prepare_sections(struct GlobalVars *gv)
/* prepare sections for receiving code in pass 2 */
{
struct Section *nexts,*sec=(struct Section *)gv->sectionlist.first;
while (nexts = (struct Section *)sec->n.next) {
sec->size = sec->pc;
sec->pc = 0;
if (!(sec->flags & SF_UNINITIALIZED))
if (sec->size)
sec->data = sec->contents = alloc((size_t)sec->size);
sec = nexts;
}
}
void exec_pass2(struct GlobalVars *gv)
{
gv->absline = 0;
gv->pass = 1;
prepare_sections(gv);
pass2(gv,get_source(gv),NULL,NULL); /* <standard sections> */
if (!gv->noregsymbols)
pass2(gv,get_source(gv),NULL,NULL); /* <standard definitions> */
if (gv->usrdefs)
pass2(gv,get_source(gv),NULL,NULL); /* <user definitions> */
if (!gv->noextmnemo)
pass2(gv,get_source(gv),NULL,NULL); /* <extended mnemonics> */
pass2(gv,get_source(gv),NULL,NULL);
if (gv->vc) {
activate_section(gv,(struct Section *)gv->sectionlist.first);
alignment(gv,2);
store_word(gv,0x76626363);
}
}
void pass2(struct GlobalVars *gv,struct SourceText *srctxt,
struct MacroParams *macro,struct SourceThread *prev_st)
/* Assembler Pass 2 */
{
struct SourceThread st;
unsigned long nlines = srctxt->nlines;
struct ParsedLine *pl = srctxt->plin;
uint32 oldnarg;
/* init SourceThread structure */
st.prev = prev_st;
st.macro = macro;
st.csource = srctxt;
st.line = 1;
gv->cthread = &st; /* set current source thread */
while (nlines--) {
gv->absline++;
st.lineptr = pl->lineptr;
/* evaluate opcode field */
switch (pl->type) {
case OT_INSTRUCTION:
instr(gv,pl);
break;
case OT_DIRECTIVE:
(((struct Directive *)pl->opcode)->dfunct)(gv,pl);
break;
case OT_MACRO:
oldnarg = gv->nargsym->value;
gv->nargsym->value = (uint32)pl->narg;
pass2(gv,get_source(gv),(struct MacroParams *)gv,gv->cthread);
/* the MacroParams pointer is set to gv, because we */
/* only need a non-zero pointer here... */
gv->nargsym->value = oldnarg;
break;
case OT_SECTION:
activate_section(gv,(struct Section *)pl->opcode);
break;
}
if (!(pl->flags&PLF_NONEWLINE))
st.line++;
++pl;
}
gv->cthread = prev_st;
}
struct SourceText *get_source(struct GlobalVars *gv)
{
return ((struct SourceText *)remhead(&gv->sourcelist));
}